﻿//IPnLStatisticParameter.cs
//Copyright (c) 2013 StockSharp LLC, all rights reserved.
//This code module is part of StockSharp library.
//This code is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
//See the file License.txt for the license details.
//More info on: http://stocksharp.com

namespace StockSharp.Algo.Statistics
{
	using System;
	using System.ComponentModel;

	using Ecng.Serialization;

	/// <summary>
	/// Интерфейс, описывающий параметр статистики, рассчитывающийся на основе значение прибыли-убытка (максимальная просадка, коэффициент Шарпа и т.д.).
	/// </summary>
	public interface IPnLStatisticParameter
	{
		/// <summary>
		/// Добавить в параметр новые данные.
		/// </summary>
		/// <param name="marketTime">Биржевое время.</param>
		/// <param name="pnl">Значение прибыли убытка.</param>
		void Add(DateTime marketTime, decimal pnl);
	}

	/// <summary>
	/// Максимальная значение прибыли за весь период.
	/// </summary>
	[DisplayName(@"Максимальная значение прибыли за весь период")]
	public class MaxProfitParameter : BaseStatisticParameter<decimal>, IPnLStatisticParameter
	{
		/// <summary>
		/// Добавить в параметр новые данные.
		/// </summary>
		/// <param name="marketTime">Биржевое время.</param>
		/// <param name="pnl">Значение прибыли убытка.</param>
		public void Add(DateTime marketTime, decimal pnl)
		{
			Value = Math.Max(Value, pnl);
		}
	}

	/// <summary>
	/// Максимальная абсолютная просадка за весь период.
	/// </summary>
	[DisplayName(@"Максимальная абсолютная просадка за весь период")]
	public class MaxDrawdownParameter : BaseStatisticParameter<decimal>, IPnLStatisticParameter
	{
		private decimal _maxEquity = decimal.MinValue;

		/// <summary>
		/// Добавить в параметр новые данные.
		/// </summary>
		/// <param name="marketTime">Биржевое время.</param>
		/// <param name="pnl">Значение прибыли убытка.</param>
		public void Add(DateTime marketTime, decimal pnl)
		{
			_maxEquity = Math.Max(_maxEquity, pnl);
			Value = Math.Max(Value, _maxEquity - pnl);
		}

		/// <summary>
		/// Сохранить состояние параметра статистики.
		/// </summary>
		/// <param name="storage">Хранилище.</param>
		public override void Save(SettingsStorage storage)
		{
			storage.SetValue("MaxEquity", _maxEquity);
			base.Save(storage);
		}

		/// <summary>
		/// Загрузить состояние параметра статистики.
		/// </summary>
		/// <param name="storage">Хранилище.</param>
		public override void Load(SettingsStorage storage)
		{
			_maxEquity = storage.GetValue<decimal>("MaxEquity");
			base.Load(storage);
		}
	}

	/// <summary>
	/// Максимальная относительная просадка эквити за весь период.
	/// </summary>
	[DisplayName(@"Максимальная относительная просадка эквити за весь период")]
	public class MaxRelativeDrawdownParameter : BaseStatisticParameter<decimal>, IPnLStatisticParameter
	{
		private decimal _maxEquity = decimal.MinValue;

		/// <summary>
		/// Добавить в параметр новые данные.
		/// </summary>
		/// <param name="marketTime">Биржевое время.</param>
		/// <param name="pnl">Значение прибыли убытка.</param>
		public void Add(DateTime marketTime, decimal pnl)
		{
			_maxEquity = Math.Max(_maxEquity, pnl);

			var drawdown = _maxEquity - pnl;
			Value = Math.Max(Value, _maxEquity != 0 ? drawdown / _maxEquity : 0);
		}

		/// <summary>
		/// Сохранить состояние параметра статистики.
		/// </summary>
		/// <param name="storage">Хранилище.</param>
		public override void Save(SettingsStorage storage)
		{
			storage.SetValue("MaxEquity", _maxEquity);
			base.Save(storage);
		}

		/// <summary>
		/// Загрузить состояние параметра статистики.
		/// </summary>
		/// <param name="storage">Хранилище.</param>
		public override void Load(SettingsStorage storage)
		{
			_maxEquity = storage.GetValue<decimal>("MaxEquity");
			base.Load(storage);
		}
	}

	/// <summary>
	/// Относительная прибыль за весь отрезок времени.
	/// </summary>
	[DisplayName(@"Относительная прибыль за весь отрезок времени")]
	public class ReturnParameter : BaseStatisticParameter<decimal>, IPnLStatisticParameter
	{
		private decimal? _firstPnL;

		/// <summary>
		/// Добавить в параметр новые данные.
		/// </summary>
		/// <param name="marketTime">Биржевое время.</param>
		/// <param name="pnl">Значение прибыли убытка.</param>
		public void Add(DateTime marketTime, decimal pnl)
		{
			if (_firstPnL == null)
				_firstPnL = pnl;

			var firstData = _firstPnL.Value;
			Value = firstData == 0 ? 0 : (pnl - firstData) / firstData;
		}

		/// <summary>
		/// Сохранить состояние параметра статистики.
		/// </summary>
		/// <param name="storage">Хранилище.</param>
		public override void Save(SettingsStorage storage)
		{
			storage.SetValue("FirstPnL", _firstPnL);
			base.Save(storage);
		}

		/// <summary>
		/// Загрузить состояние параметра статистики.
		/// </summary>
		/// <param name="storage">Хранилище.</param>
		public override void Load(SettingsStorage storage)
		{
			_firstPnL = storage.GetValue<decimal?>("FirstPnL");
			base.Load(storage);
		}
	}

	/// <summary>
	/// Коэффициент восстановления (чистая прибыль / максимальная просадка).
	/// </summary>
	[DisplayName(@"Коэффициент восстановления (чистая прибыль / максимальная просадка)")]
	public class RecoveryFactorParameter : BaseStatisticParameter<decimal>, IPnLStatisticParameter
	{
		private decimal _maxEquity = decimal.MinValue;
		private decimal _maxDrawdown = decimal.MinValue;

		private decimal? _firstPnL;

		/// <summary>
		/// Добавить в параметр новые данные.
		/// </summary>
		/// <param name="marketTime">Биржевое время.</param>
		/// <param name="pnl">Значение прибыли убытка.</param>
		public void Add(DateTime marketTime, decimal pnl)
		{
			if (_firstPnL == null)
				_firstPnL = pnl;

			_maxEquity = Math.Max(_maxEquity, pnl);
			_maxDrawdown = Math.Max(Value, _maxEquity - pnl);

			var firstData = _firstPnL.Value;
			Value = _maxDrawdown != 0 ? (pnl - firstData) / _maxDrawdown : 0;
		}

		/// <summary>
		/// Сохранить состояние параметра статистики.
		/// </summary>
		/// <param name="storage">Хранилище.</param>
		public override void Save(SettingsStorage storage)
		{
			storage.SetValue("MaxEquity", _maxEquity);
			storage.SetValue("MaxDrawdown", _maxDrawdown);
			storage.SetValue("FirstPnL", _firstPnL);

			base.Save(storage);
		}

		/// <summary>
		/// Загрузить состояние параметра статистики.
		/// </summary>
		/// <param name="storage">Хранилище.</param>
		public override void Load(SettingsStorage storage)
		{
			_maxEquity = storage.GetValue<decimal>("MaxEquity");
			_maxDrawdown = storage.GetValue<decimal>("MaxDrawdown");
			_firstPnL = storage.GetValue<decimal?>("FirstPnL");

			base.Load(storage);
		}
	}

	/// <summary>
	/// Чистая прибыль за весь отрезок времени.
	/// </summary>
	[DisplayName(@"Чистая прибыль за весь отрезок времени")]
	public class NetProfitParameter : BaseStatisticParameter<decimal>, IPnLStatisticParameter
	{
		private decimal? _firstPnL;

		/// <summary>
		/// Добавить в параметр новые данные.
		/// </summary>
		/// <param name="marketTime">Биржевое время.</param>
		/// <param name="pnl">Значение прибыли убытка.</param>
		public void Add(DateTime marketTime, decimal pnl)
		{
			if (_firstPnL == null)
				_firstPnL = pnl;

			var firstData = _firstPnL.Value;
			Value = pnl - firstData;
		}

		/// <summary>
		/// Сохранить состояние параметра статистики.
		/// </summary>
		/// <param name="storage">Хранилище.</param>
		public override void Save(SettingsStorage storage)
		{
			storage.SetValue("FirstPnL", _firstPnL);
			base.Save(storage);
		}

		/// <summary>
		/// Загрузить состояние параметра статистики.
		/// </summary>
		/// <param name="storage">Хранилище.</param>
		public override void Load(SettingsStorage storage)
		{
			_firstPnL = storage.GetValue<decimal?>("FirstPnL");
			base.Load(storage);
		}
	}
}